package haoji_juc.xujiahuanxing;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @program: Dome
 * @description:
 * @className: DomeCondition
 * @author: rjt99999
 * @version: 1.0.0
 * @create: 2020-08-04 15:48
 **/
public class DomeCondition {


    public static void main(String[] args) {

        Ckerk1 ckerk1 = new Ckerk1();

        consumer1 consumer1 = new consumer1(ckerk1);

        Productor1 productor1 = new Productor1(ckerk1);

        new Thread( consumer1,"消费者a").start();
        new Thread(productor1, "生产者a").start();
        new Thread(consumer1, "消费者b").start();
        new Thread(productor1,"生产者b").start();


    }
    /**
     * Condition提供了一系列的方法来对阻塞和唤醒线程(线程通信)：

     await() ：造成当前线程在接到信号或被中断之前一直处于等待状态。
     await(long time, TimeUnit unit) ：造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
     awaitNanos(long nanosTimeout) ：造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。返回值表示剩余时间，如果在nanosTimesout之前唤醒，那么返回值 = nanosTimeout - 消耗时间，如果返回值 <= 0 ,则可以认定它已经超时了。
     awaitUninterruptibly() ：造成当前线程在接到信号之前一直处于等待状态。【注意：该方法对中断不敏感】。
     awaitUntil(Date deadline) ：造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。如果没有到指定时间就被通知，则返回true，否则表示到了指定时间，返回返回false。
     signal()：唤醒一个等待线程。该线程从等待方法返回前必须获得与Condition相关的锁。
     signal()All：唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。
     *
     *
     * Condition是一种广义上的条件队列。他为线程提供了一种更为灵活的等待/通知模式，线程在调用await方法后执行挂起操作，直到线程等待的某个条件为真时才会被唤醒。
     * Condition必须要配合锁一起使用，因为对共享状态变量的访问发生在多线程环境下。
     * 一个Condition的实例必须与一个Lock绑定，因此Condition一般都是作为Lock的内部实现
     *
     */


    /*
    lock 与 objcet  线程通信之间的区别和共同？
     */
}

class Ckerk1 {

    private int product = 0;

    private Lock lock = new ReentrantLock();



    private Condition condition = lock.newCondition();

    //进货
    public void get() {

        lock.lock();

        try {

            while (product >= 1) {

                System.out.println("货已满");

                try {
                    //也要放于循环之中
                    condition.await();//一个Condition的实例必须与一个Lock绑定，因此Condition一般都是作为Lock的内部实现

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

            System.out.println(Thread.currentThread().getName() + ":" + ++product);

            condition.signalAll();

        } finally {
            //一般解锁动作放于（一定要执行此操作） finally-一定回执行
            lock.unlock();

        }
    }

    public void sale() {
        lock.lock();

        try {
            while (product <= 0) {

                System.out.println("缺货");

                try {
                    condition.await();

                } catch (InterruptedException e) {

                    e.printStackTrace();
                }


            }

            System.out.println(Thread.currentThread().getName() + ":" + --product);

            condition.signal();
        } finally {

            lock.unlock();

        }
    }


}

//生产者
class Productor1 implements Runnable {

    private Ckerk1 ckerk1;


    public Productor1(Ckerk1 ckerk1) {
        this.ckerk1 = ckerk1;
    }

    @Override
    public void run() {


        for (int i = 0; i < 20; i++) {

            ckerk1.get();

        }


    }
}


//消费者
class consumer1 implements Runnable {

    private Ckerk1 ckerk1;

    public consumer1(Ckerk1 ckerk1) {
        this.ckerk1 = ckerk1;
    }

    @Override
    public void run() {

        for (int i = 0; i < 20; i++) {


            ckerk1.sale();
        }

    }
}

